---@class GT.ability
---@field ability Ability 技能
---@field binding ABILITY_FLOAT_ATTRS_KEY 绑定值
---@field u GT.unit 拥有这个技能的单位
---@field attr table<uKeyAttr,number> 属性
GT.ability = class()

---@class ability_data
---@field ability Ability 技能

---@class ABILITY_FLOAT_ATTRS 技能属性
ABILITY_FLOAT_ATTRS = {
    ['魔法消耗'] = 'ability_cost',
    ['冷却时间'] = 'cold_down_time',
    ['施法距离'] = 'ability_cast_range',
    ['施法开始时间'] = 'ability_cast_point',
    ['施法引导时间'] = 'ability_prepare_time',
    ['施法出手时间'] = 'ability_channel_time',
    ['施法完成时间'] = 'ability_bw_point',
    ['充能冷却'] = 'ability_stack_cd',
    ['最大充能数'] = 'ability_max_stack_count',
    ['魔法消耗'] = 'ability_cost',
    ['技能伤害值'] = 'ability_damage',
}
---@class ABILITY_FLOAT_ATTRS_KEY 技能属性Key值
ABILITY_FLOAT_ATTRS_KEY = {
    ['魔法消耗'] = '魔法消耗',
    ['冷却时间'] = '冷却时间',
    ['施法距离'] = '施法距离',
    ['施法开始时间'] = '施法开始时间',
    ['施法引导时间'] = '施法引导时间',
    ['施法出手时间'] = '施法出手时间',
    ['施法完成时间'] = '施法完成时间',
    ['充能冷却'] = '充能冷却',
    ['最大充能数'] = '最大充能数',
    ['魔法消耗'] = '魔法消耗',
    ['技能伤害值'] = '技能伤害值',
}

---@param a Ability
function GT.ability:ctor(a)
    self.ability = a
    self.bind = new(bind, self)
    self.binding = self.bind.bindable
    self.u = self:api_get_owner()
    self.attr = OrderedTable()

    for k, v in pairs(ABILITY_FLOAT_ATTRS) do
        self[k] = self:api_get_float_attr(k)
        self.bind:add_({
            key = '=' .. k,
            func = function(val, old)
                if val == nil then
                    return
                end
                self[k] = val
                self:api_set_str_attr(v, self[k])
            end
        })
        self.bind:add_({
            key = k,
            func = function(val, old)
                if val == nil then
                    return
                end
                self[k] = val
                self:api_set_str_attr(v, self[k])
            end
        })
        self.bind:add_({
            key = '+' .. k,
            func = function(val, old)
                if val == nil then
                    return
                end

                self[k] = self[k] + val

                self:api_set_str_attr(v, self[k])
            end
        })
        self.bind:add_({
            key = '-' .. k,
            func = function(val, old)
                if val == nil then
                    return
                end
                self[k] = self[k] - val
                self:api_set_str_attr(v, self[k])
            end
        })
    end
end

---技能转字符串
---@return AbilityID
function GT.ability:__tostring()
    return global_api.ability_to_str(self.ability)
end

---技能转字符串
---@param a Ability 技能实体 
---@return AbilityID
function GT.ability.tostring(a)
    return global_api.ability_to_str(a)
end


---转对象
---@param ability Ability
---@return GT.ability
function GT.ability.obj(ability)
    if ability == nil then
        return nil
    end
    local skid = GT.ability.tostring(ability)
    local obj = all_cache:get(skid)

    if obj == nil then
        obj = new(GT.ability, ability)
        all_cache:set(skid, obj)
    end
    return obj
end

---技能 tip
function GT.ability:tip()
    return StringBuilder.new():append_line(GT.tip.attr(self.attr)):append_line(GT.abilityInit.event_tip(self:get_AbilityKey())):append_line(self:desc()):append_line(''):tostring(true)
end

--- 获取技能字符串属性
---@param attr ABILITY_FLOAT_ATTRS 标记名
---@return Str
function GT.ability:api_get_str_attr(attr)
    self.ability.api_get_str_attr(attr)
end

--- 设置技能字符串属性
---@param attr ABILITY_FLOAT_ATTRS 标记名
---@param value Str 字符串值
function GT.ability:api_set_str_attr(attr, value)
    self.ability.api_set_str_attr(attr, value)
end

--- 设置技能名字
---@param value Str 字符串值
function GT.ability:api_set_name(value)
    self.ability.api_set_name(value)
end

--- 获取技能拥有者
---@return GT.unit
function GT.ability:api_get_owner()
    return GT.unit.obj(self.ability.api_get_owner())
end

--- 获取技能拥有者id
---@return UnitID
function GT.ability:api_get_owner_id()
    return self.ability.api_get_owner_id()
end

--- 获取技能拥有者单位
---@return GT.unit
function GT.ability:api_get_owner_unit()
    return GT.unit.get_unit_by_id(self.ability.api_get_owner_id())
end

--- 获取技能类型
---@return AbilityType
function GT.ability:api_get_type()
    return self.ability.api_get_type()
end

---获取技能类型公式属性
---@param attr_name ABILITY_FLOAT_ATTRS 属性名字
---@return number
function GT.ability:get_ability_type_formula_attr(attr_name)
    return game_api.get_ability_conf_formula_attr(self:get_AbilityKey(), attr_name, 1, 0, nil, nil):float()
end

---获取技能类型公式属性
---@param ak AbilityKey 技能编号
---@param attr_name ABILITY_FLOAT_ATTRS 属性名字
---@return number
function GT.ability.get_ability_type_formula_attr_by_id(ak, attr_name)
    return game_api.get_ability_conf_formula_attr(ak, attr_name, 1, 0, nil, nil)
end

--- 获取技能类型
---@return AbilityIndex
function GT.ability:api_get_ability_index()
    return self.ability.api_get_ability_index()
end

--- 获取技能拥有者
---@return AbilitySeq
function GT.ability:api_get_ability_seq()
    return self.ability.api_get_ability_seq()
end

--- 获取技能释放类型
---@return AbilityCastType
function GT.ability:api_get_ability_cast_type()
    return self.ability.api_get_ability_cast_type()
end

--- 移除技能
function GT.ability:api_remove()
    self.ability.api_remove()
end

--- 获取技能的等级
---@return Int32
function GT.ability:lv()
    return self.ability.api_get_level()
end

--- 是否拥有标记
---@param tag Str 标记名
---@return Bool
function GT.ability:has_tag(tag)
    return self.ability.has_tag(tag)
end

--- 移除键值对
---@param k Str 键
function GT.ability:api_remove_kv(k)
    self.ability.api_remove_kv(k)
end

--- 计算公式类型KV
---@param k Str 键
---@return Fixed
function GT.ability:api_calc_ability_formula_kv(k)
    return self.ability.api_calc_ability_formula_kv(k)
end

--- 技能对象是否拥有目标
---@param runtime_id Int32 runtime_id
---@return Bool
function GT.ability:api_has_target(runtime_id)
    return self.ability.api_has_target(runtime_id)
end

--- 获取技能释放的点
---@param runtime_id Int32 runtime_id
---@return FPoint
function GT.ability:api_get_release_position(runtime_id)
    return GT.point.obj(self.ability.api_get_release_position(runtime_id))
end

--- 获取技能释放的方向
---@param runtime_id Int32 runtime_id
---@return Fixed
function GT.ability:api_get_release_direction(runtime_id)
    return self.ability.api_get_release_direction(runtime_id)
end

--- 获取技能实数属性值
---@param attr ABILITY_FLOAT_ATTRS 属性名
---@return number
function GT.ability:api_get_float_attr(attr)
    return self.ability.api_get_float_attr(attr):float()
end

--- 获取技能整数属性值
---@param attr ABILITY_FLOAT_ATTRS 属性名
---@return Int32
function GT.ability:api_get_int_attr(attr)
    return self.ability.api_get_int_attr(attr)
end

--- 冷却
---@return Int32
function GT.ability:cd()
    return self:api_get_int_attr(ABILITY_FLOAT_ATTRS['冷却时间'])
end

--- 消耗
---@return Int32
function GT.ability:cost(attr)
    return self:api_get_int_attr(ABILITY_FLOAT_ATTRS['魔法消耗'])
end

--- 获取技能布尔属性值
---@param attr ABILITY_FLOAT_ATTRS 属性名
---@return Bool
function GT.ability:api_get_bool_attr(attr)
    return self.ability.api_get_bool_attr(attr)
end

--- 获取技能释放范围
---@return Fixed
function GT.ability:api_get_ability_cast_range()
    return self.ability.api_get_ability_cast_range()
end

--- 设置技能释放范围
---@param value Fixed 释放范围
function GT.ability:api_set_ability_cast_range(value)
    self.ability.api_set_ability_cast_range(value)
end

--- 设置扇形指示器半径
---@param value Fixed 指示器半径
function GT.ability:api_set_ability_sector_radius(value)
    self.ability.api_set_ability_sector_radius(value)
end

--- 设置扇形指示器角度
---@param value Fixed 指示器角度
function GT.ability:api_set_ability_sector_angle(value)
    self.ability.api_set_ability_sector_angle(value)
end

--- 设置箭头/多段指示器宽度
---@param value Fixed 释放范围
function GT.ability:api_set_ability_arrow_width(value)
    self.ability.api_set_ability_arrow_width(value)
end

--- 设置箭头/多段指示器长度
---@param value Fixed 释放范围
function GT.ability:api_set_ability_arrow_length(value)
    self.ability.api_set_ability_arrow_length(value)
end

--- 设置圆形指示器半径
---@param value Fixed 释放范围
function GT.ability:api_set_ability_circle_radius(value)
    self.ability.api_set_ability_circle_radius(value)
end

--- 设置技能指示器类型
---@param pointer_type Fixed 释放范围
function GT.ability:api_set_ability_pointer_type(pointer_type)
    self.ability.api_set_ability_pointer_type(pointer_type)
end

--- 获取技能玩家属性消耗
---@param attr Str 玩家属性名
---@return Fixed
function GT.ability:api_get_ability_player_attr_cost(attr)
    return self.ability.api_get_ability_player_attr_cost(attr):int()
end

--- 设置技能玩家属性消耗
---@param attr Str 玩家属性名
---@param value Fixed 玩家属性消耗
function GT.ability:api_set_ability_player_attr_cost(attr, value)
    self.ability.api_set_ability_player_attr_cost(attr, value)
end

--- 增加技能玩家属性消耗
---@param attr Str 玩家属性名
---@param value Fixed 玩家属性消耗
function GT.ability:api_add_ability_player_attr_cost(attr, value)
    self.ability.api_add_ability_player_attr_cost(attr, value)
end

--- 设置技能等级
---@param level Int32 技能等级
function GT.ability:api_set_level(level)
    self.ability.api_set_level(level)
end

--- 学习技能
function GT.ability:api_learn_ability()
    self.ability.api_learn_ability()
end

--- 增加技能等级
---@param level Int32 技能等级
function GT.ability:api_add_level(level)
    self.ability.api_add_level(level)
end

--- 增量修改技能实数属性值
---@param attr Str 属性名
---@param value Fixed 实数属性值
function GT.ability:api_add_float_attr(attr, value)
    self.ability.api_add_float_attr(attr, value)
end

--- 设置技能实数属性值
---@param attr Str 属性名
---@param value Fixed 实数属性值
function GT.ability:api_set_float_attr(attr, value)
    self.ability.api_set_float_attr(attr, value)
end

--- 增量修改技能整数属性值
---@param attr Str 属性名
---@param value Int32 整数属性值
function GT.ability:api_add_int_attr(attr, value)
    self.ability.api_add_int_attr(attr, value)
end

--- 设置技能整数属性值
---@param attr Str 属性名
---@param value Int32 整数属性值
function GT.ability:api_set_int_attr(attr, value)
    self.ability.api_set_int_attr(attr, value)
end

--- 设置技能布尔属性值
---@param attr Str 属性名
---@param value Bool 布尔属性值
function GT.ability:api_set_bool_attr(attr, value)
    self.ability.api_set_bool_attr(attr, value)
end

--- 阻止当前技能施法
function GT.ability:api_break_ability_in_cs()
    self.ability.api_break_ability_in_cs()
end

--- 获取技能编号
---@return AbilityKey
function GT.ability:get_AbilityKey()
    return self.ability.api_get_ability_id()
end

--- 是否是近战技能
---@return Bool
function GT.ability:api_is_melee_ability()
    return self.ability.api_is_melee_ability()
end

--- 是否是普攻
---@return Bool
function GT.ability:api_is_common_atk()
    return self.ability.api_is_common_atk()
end

--- 是否是被动
---@return Bool
function GT.ability:is_passive_ability()
    return self.ability.is_passive_ability()
end

--- 获取消耗生命是否致死
---@return Bool
function GT.ability:api_get_cost_hp_can_die()
    return self.ability.api_get_cost_hp_can_die()
end

--- 设置消耗生命是否致死
---@param value Bool 能否释放
function GT.ability:api_set_cost_hp_can_die(value)
    self.ability.api_set_cost_hp_can_die(value)
end

--- 获取生命不足能否施放
---@return Bool
function GT.ability:api_get_can_cast_when_hp_insufficient()
    return self.ability.api_get_can_cast_when_hp_insufficient()
end

--- 设置生命不足能否施放
---@param value Bool 能否释放
function GT.ability:api_set_can_cast_when_hp_insufficient(value)
    self.ability.api_set_can_cast_when_hp_insufficient(value)
end

--- 获取技能名称
---@return Str
function GT.ability:name()
    return self.ability.api_get_name()
end

--- 设置技能是否受冷却缩减影响
---@param value Bool 布尔属性值
function GT.ability:api_set_influenced_by_cd_reduce(value)
    self.ability.api_set_influenced_by_cd_reduce(value)
end

--- 是否受冷却缩减影响
---@return Bool
function GT.ability:api_get_influenced_by_cd_reduce()
    return self.ability.api_get_influenced_by_cd_reduce()
end

--- 获取技能的充能层数
---@return Int32
function GT.ability:api_get_ability_stack()
    return self.ability.api_get_ability_stack()
end

--- 增加技能充能层数
---@param value Int32 充能层数
function GT.ability:api_add_ability_stack_count(value)
    self.ability.api_add_ability_stack_count(value)
end

--- 设置技能充能层数
---@param value Int32 充能层数
function GT.ability:api_set_ability_stack_count(value)
    self.ability.api_set_ability_stack_count(value)
end

--- 获取当前技能剩余冷却时间
---@return Fixed
function GT.ability:cd()
    return self.ability.api_get_cd_left_time():float()
end

--- 技能立即冷却
function GT.ability:api_immediately_clear_cd()
    self.ability.api_immediately_clear_cd()
end

--- 改变技能冷却时间
---@param value Fixed 冷却时间
function GT.ability:api_change_ability_cd_cold_down(value)
    self.ability.api_change_ability_cd_cold_down(value)
end

--- 设置技能冷却时间
---@param value Fixed 冷却时间
function GT.ability:api_set_ability_cd(value)
    self.ability.api_set_ability_cd(value)
end

--- 增加技能冷却时间
---@param value Fixed 冷却时间
function GT.ability:api_add_ability_cd(value)
    self.ability.api_add_ability_cd(value)
end

--- 从头开始冷却
function GT.ability:api_restart_cd()
    self.ability.api_restart_cd()
end

--- 改变当次充能时间
---@param value Fixed 冷却时间
function GT.ability:api_set_ability_cur_stack_cd(value)
    self.ability.api_set_ability_cur_stack_cd(value)
end

--- 获取技能当前剩余充能时间
---@return Fixed
function GT.ability:api_get_stack_cd_left_time()
    return self.ability.api_get_stack_cd_left_time()
end

--- 启用技能
function GT.ability:api_enable()
    self.ability.api_enable()
end

--- 禁用技能
function GT.ability:api_disable()
    self.ability.api_disable()
end

--- 对技能所属单位的所属玩家关系播放音乐
---@param camp_target RoleRelation 玩家关系
---@param sid AudioKey 乐曲编号
---@param loop Bool 是否循环
function GT.ability:api_play_sound_by_ability_for_role_relation(camp_target, sid, loop)
    self.ability.api_play_sound_by_ability_for_role_relation(camp_target, sid, loop)
end

--- 获取技能icon图标的图片id
---@return Int32
function GT.ability:icon_id()
    return game_api.get_icon_id_by_ability_type(self:get_AbilityKey())
end

--- 获取技能icon图标的图片id
---@return Int32
function GT.ability.icon_id_key(key)
    return game_api.get_icon_id_by_ability_type(key)
end

--- 返回指定技能类型的描述
---@return Str
function GT.ability:desc()
    return game_api.get_ability_desc_by_type(self:get_AbilityKey())
end

--- 返回指定技能类型的描述
---@return Str
function GT.ability.desc_key(key)
    return game_api.get_ability_desc_by_type(key)
end

--- 返回指定技能类型的名称
---@return Str
function GT.ability:get_ability_name_by_type()
    return game_api.get_ability_name_by_type(self:get_AbilityKey())
end

--- 返回指定技能类型的名称
---@return Str
function GT.ability.get_ability_name_by_key(key)
    return game_api.get_ability_name_by_type(key)
end

--- 获取技能最大等级
---@return Int32
function GT.ability:get_ability_max_level()
    return game_api.get_ability_max_level(self.ability)
end

--- 技能实体是否存在
---@param ability GT.ability 技能
---@return Bool
function GT.ability.isNull(ability)
    return game_api.ability_is_exist(ability.ability)
end

--- 技能选取的目标单位
---@param runtime_id Int32 runtime_id
---@return GT.unit
function GT.ability:get_target_unit_in_ability(runtime_id)
    return GT.unit.obj(game_api.get_target_unit_in_ability(self.ability, runtime_id))
end

--- 技能选取的目标物品
---@param runtime_id Int32 runtime_id
---@return GT.item
function GT.ability:get_target_item_in_ability(runtime_id)
    return GT.item.obj(game_api.get_target_item_in_ability(self.ability, runtime_id))
end

--- 技能选取的目标可破坏物
---@param ability Ability 技能
---@param runtime_id Int32 runtime_id
---@return GT.destructible
function GT.ability:get_target_dest_in_ability(runtime_id)
    return GT.destructible.obj(game_api.get_target_dest_in_ability(self.ability, runtime_id))
end

--- 技能类型是否受冷却缩减影响
---@return Bool
function GT.ability:api_get_influenced_by_cd_reduce(ability_id)
    return game_api.api_get_influenced_by_cd_reduce(ability_id)
end

---@generic K
---@generic V
---创建自定义值 取值 直接 对象['K'] 修改为 对象.binding['K']
---@param k K
---@param v V
---@param call kv_call
function GT.ability:set(k, v, call)
    self[k] = v
    if call == nil then
        return
    end
    self.bind:add_({
        key = k,
        func = function(val, old)
            if val == nil then
                return
            end
            self[k] = val
            call(k, val, old)
        end
    })
end

---获得技能
---@param key AbilityKey 技能编号key
---@param fun ABILITY_OBTAIN 回调
function GT.ability.event_add_ability(key, fun)
    return GT.event.ABILITY_OBTAIN(function(u, a)
        if a:get_AbilityKey() == key then
            fun(u, a)
        end
    end)
end

---获得技能
---@param key AbilityKey 技能编号key
---@param fun ABILITY_OBTAIN 回调
function GT.ability.event_add_ability(key, fun)
    return GT.event.ABILITY_OBTAIN(function(u, a)
        if a:get_AbilityKey() == key then
            fun(u, a)
        end
    end)
end

---@class abilityBtn:selectUi_data 技能展示选择
---@field key AbilityKey 技能编号
---@field enter_eve UI_EVENT 进入事件
---@field leave_eve UI_EVENT 离开事件

---根据技能编号创建按钮
---@param d abilityBtn
---@return GT.ui.model.selectUi
function GT.ability.toBtn(d)
    local key = d.key

    local b = GT.ui.model.selectUi.obj({
        x = d.x,
        y = d.y,
        icon = GT.ability.icon_id_key(d.key),
        enter =d.enter_eve ,
        leave =d.leave_eve ,
        click = d.click,
        parent = d.parent,
        show = d.show
    })

    -- function(data, player, ui)
    --     local gold = 0
    --     local pop = 0
    --     if abilityInit[key] ~= nil then
    --         gold = abilityInit[key].playerKv[Game.res_type['金币']] or 0
    --         pop = abilityInit[key].playerKv[Game.res_type['人口']] or 0
    --     end

    --     ---@type GT.ui.model.selectUi
    --     local u = ui
    --     u:set(player, {
    --         icon = GT.ability.icon_id_key(key),
    --         name = GT.ability.get_ability_name_by_key(key),
    --         text = GT.ability.desc_key(key),
    --         lv = 0,
    --         cd = 0,
    --         gold = gold,
    --         pop = pop,
    --     })
    -- end


    -- function(data, player, ui)
    --     ---@type GT.ui.model.selectUi
    --     local u = ui
    --     u:hide(player)
    -- end
    return b
end
